<template>
  <div class="map">
    <div v-show="false">
      <LocateIcon ref="locateIcon" />
    </div>
    <div id="map-container" class="map-container"></div>

    <!-- 定位失败 -->
    <template v-if="showError">
      <div class="map-error">
        <div class="error_title">定位服务未开启</div>
        <div class="error_desc">无法获取您的当前位置，请打开您的位置定位</div>
        <div class="error_btn">
          <Button
            @click="$emit('cancel')"
            type="primary"
            block
            plain
            class="!rounded-10px"
          >
            返回
          </Button>
          <Button
            @click="_getLocation"
            type="primary"
            block
            class="!rounded-10px !ml-7px"
          >
            打开定位
          </Button>
        </div>
      </div>
    </template>

    <template v-else>
      <!-- 搜索 -->
      <div v-if="type === 'search'" class="map-search">
        <div class="search_toolbar">
          <button
            type="button"
            @click="$emit('cancel')"
            class="toolbar__cancel"
          >
            取消
          </button>
          <button type="button" @click="_confirm" class="toolbar__confirm">
            确定
          </button>
        </div>
        <div>
          <form action="/">
            <Search
              v-model="keyword"
              @input="_onSearch"
              class="!pt-0"
              placeholder="搜索地点"
            />
          </form>
        </div>
        <div class="search_result">
          <RadioGroup v-model="selectPoiId" @change="_moveSelect">
            <Cell
              v-for="item in poiList"
              :key="item.id"
              :title="item.name"
              clickable
              @click="selectPoiId = item.id"
            >
              <template #right-icon>
                <Radio :name="item.id" />
              </template>
            </Cell>
          </RadioGroup>
        </div>
      </div>
      <!-- 签到 -->
      <div v-if="type === 'clock-in'" class="map-clock-in">
        <div class="clock_title">签到</div>
        <div class="px-16px py-20px">
          <div class="clock_location">
            <div class="clock_location__title">当前位置</div>
            <div class="clock_location__address">
              <div v-if="isFar" class="mr-5px">
                <Icon name="warning" color="#F55F4E" />
              </div>
              <div class="address">
                {{ _showformattedAddress() }}
              </div>
            </div>
          </div>
          <div class="clock_btn">
            <Button
              @click="$emit('cancel')"
              type="primary"
              block
              plain
              class="!rounded-10px"
            >
              返回
            </Button>
            <Button
              @click="_confirm"
              type="primary"
              block
              :disabled="isFar || !this.loadingCompleted"
              class="!rounded-10px !ml-7px"
            >
              确认签到
            </Button>
          </div>
        </div>
      </div>
      <!-- 签出 -->
      <div v-if="type === 'clock-out'" class="map-clock-out">
        <div class="clock_title">签出</div>
        <div class="px-16px py-20px">
          <div class="clock_location">
            <div class="clock_location__title">当前位置</div>
            <div class="clock_location__address">
              <div v-if="isFar" class="mr-5px">
                <Icon name="warning" color="#F55F4E" />
              </div>
              <div class="address">
                {{ _showformattedAddress() }}
              </div>
            </div>
          </div>
          <div class="clock_btn">
            <Button
              @click="$emit('cancel')"
              type="primary"
              block
              plain
              class="!rounded-10px"
            >
              返回
            </Button>
            <Button
              @click="_confirm"
              type="primary"
              block
              class="!rounded-10px !ml-7px"
            >
              {{ isFar ? "异地签出" : "确认签出" }}
            </Button>
          </div>
        </div>
      </div>
    </template>
  </div>
</template>

<script>
import AMapLoader from "@amap/amap-jsapi-loader";
import { Search, Cell, Radio, RadioGroup, Icon, Button, Toast } from "vant";
import LocateIcon from "./locate.vue";
import LocationIcon from "@/assets/icon/map-location.png";
import _ from "lodash";
import { isPlus, gotoAppSetting } from "./tool";
// 签到签出默认配置
const defaultClockOpt = {
  locationAffsetBottom: 350, // 定位按钮位置
  zoom: 14, // 初始化缩放等级  3-19
  poi: [], // 签到签出poiID
  radius: 500, // 签到范围
};

// 搜索默认配置
const defaultSearchOpt = {
  locationAffsetBottom: 20, // 定位按钮位置
  zoom: 16, // 初始化缩放等级  3-19
};

export default {
  components: {
    Search,
    Cell,
    Radio,
    RadioGroup,
    Icon,
    Button,
    LocateIcon,
  },
  props: {
    // 地图类型
    type: {
      type: String,
      default: "search",
      validator: (val) => {
        return ["search", "clock-in", "clock-out"].includes(val);
      },
    },
    // 搜索poi信息的配置
    searchOptions: {
      type: Object,
      default: () => ({}),
    },
    // 打开的配置
    clockOptions: {
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return {
      keyword: null,
      Map: null, //  map 对象
      Marker: null, // 标记对象
      Circle: null,
      PlaceSearch: null, // POI搜索插件
      locationPOI: null, // 当前定位poi
      poiList: [], // 搜索结果
      selectPoiId: null,
      distance: null, // 当前定位于签到/签出poi的距离
      showError: false,
      watchPositionId: null,
      loadingCompleted: false,
      Autocomplete: null, //输入提示功能
    };
  },
  computed: {
    isSearch() {
      return this.type === "search";
    },
    options() {
      if (this.type === "search") {
        return { ...defaultSearchOpt, ...this.searchOptions };
      }
      return { ...defaultClockOpt, ...this.clockOptions };
    },
    formattedAddress() {
      if (this.locationPOI) {
        return this.locationPOI.formattedAddress;
      }
      return "定位中";
    },
    isFar() {
      return this.distance && this.distance >= this.options.radius;
    },
  },
  mounted() {
    this._initMap();
    window.addEventListener("online", this.updateOnline);
    window.addEventListener("offline", this.updateOffline);
  },
  beforeDestroy() {
    if (this.isSearch) {
      this.Map.off("click", this._mapOnClick);
    }
    window.removeEventListener("online", this.updateOnline);
    window.removeEventListener("offline", this.updateOffline);
    this.Map && this.Map.destroy();
    clearInterval(this.watchPositionId);
    console.log("Map销毁");
  },
  methods: {
    updateOnline() {
      this._initMap();
    },
    updateOffline() {
      Toast("请开启网络后重试");
    },
    async _initMap() {
      try {
        const AMap = await AMapLoader.load({
          key: "28988c3ff6873499b3913c8934567e80", // 申请好的Web端开发者Key，首次调用 load 时必填
          version: "1.4.15", // 指定要加载的 JSAPI 的版本，缺省时默认为 1.4.15
        });
        // 生成地图
        this.Map = new AMap.Map("map-container", {
          zoom: this.options.zoom,
          mapStyle: "amap://styles/27531f8203a219e2fbc8838256a0ac28",
        });
        if (this.isSearch) {
          this.Map.on("click", this._mapOnClick);
        }

        // 异步加载插件 定位/poi搜索
        AMap.plugin(
          ["AMap.Geolocation", "AMap.PlaceSearch", "AMap.Autocomplete"],
          () => {
            // 创建marker
            this.Marker = new AMap.Marker({
              icon: new AMap.Icon({
                image: LocationIcon,
                size: new AMap.Size(20, 28),
                imageSize: new AMap.Size(20, 28),
              }),
              animation: "AMAP_ANIMATION_DROP",
              zIndex: 333,
            });
            if (!this.isSearch) {
              // 创建circle
              this.Circle = new AMap.Circle({
                radius: this.options.radius,
                strokeColor: "#1d6fe9",
                strokeWeight: 1,
                fillColor: "#1d6fe9",
                fillOpacity: 0.1,
              });
            }
            // 增加搜索插件
            this.PlaceSearch = new AMap.PlaceSearch({
              // city 指定搜索所在城市，支持传入格式有：城市名、citycode和adcode
              pageSize: 50,
              extensions: "all",
            });
            this.Autocomplete = new AMap.Autocomplete({
              datatype: "poi",
            });
            // 加载定位插件
            const geolocation = new AMap.Geolocation({
              // 是否使用高精度定位，默认：true
              enableHighAccuracy: true,
              // 设置定位超时时间，默认：无穷大
              timeout: 10000,
              // 定位按钮的停靠位置的偏移量
              buttonOffset: new AMap.Pixel(
                14,
                this.options.locationAffsetBottom
              ),
              buttonPosition: "RB",
              showCircle: false, // 签到/签出的时候显示圈
              panToLocation: this.isSearch,
              buttonDom: this.$refs.locateIcon.$el,
            });
            // 获取当前位置
            geolocation.getCurrentPosition();
            this.Map.addControl(geolocation);
            // 定位成功
            AMap.event.addListener(geolocation, "complete", async (result) => {
              // console.log(result);
              // 是否有定位失败的监听
              if (this.watchPositionId) {
                this.showError = false;
                clearInterval(this.watchPositionId);
                this.watchPositionId = null;
              }
              // 定位成功
              this.locationPOI = result;
              if (this.isSearch) {
                // const { lng, lat } = result.position;
                // 设置marker位置
                // this.Marker.setPosition(new AMap.LngLat(lng, lat));
                this.Map.add(this.Marker);
                // 知道搜索城市
                // this.PlaceSearch.setCity(result.addressComponent.citycode);
                this._onSearch();
              } else {
                const {
                  location: { lng, lat },
                } = await this._getPoiDetail(this.options.poi);

                this.Marker.setPosition(new AMap.LngLat(lng, lat));
                this.Circle.setCenter(new AMap.LngLat(lng, lat));
                this.Map.add(this.Marker);
                this.Map.add(this.Circle);
                this.Map.panTo(new AMap.LngLat(lng, lat));

                this._getDistance();
              }
            });
            // 定位失败
            AMap.event.addListener(geolocation, "error", (err) => {
              // console.log(err);
              // 定位失败
              if (!this.watchPositionId) {
                this.showError = true;
                this.watchPositionId = setInterval(() => {
                  geolocation.getCurrentPosition();
                }, 2000);
              }
            });
          }
        );
      } catch (error) {
        console.log("error: ", error);
      }
    },
    async _confirm() {
      try {
        if (this.type === "search") {
          const result = await this._getPoiDetail(this.selectPoiId);
          this.$emit("confirm", result);
        } else {
          this.$emit("clock", this.locationPOI, this.isFar);
        }
      } catch (error) {
        console.log("error: ", error);
      }
    },
    _onSearchByKeyword(val) {
      // this.PlaceSearch.search(val, (status, result) => {
      //   console.log("result111");
      //   console.log(result);
      //   if (status === "complete") {
      //     let list = result.poiList.pois || [];
      //     let obj = {};
      //     this.poiList = list.reduce((cur, next) => {
      //       obj[next.id] ? "" : (obj[next.id] = true && cur.push(next));
      //       return cur;
      //     }, []);
      //     console.log(this.poiList);
      //     this.selectPoiId = this.poiList[0].id;
      //     this._moveSelect(this.selectPoiId);
      //   }
      // });
      this.Autocomplete.search(val, (status, result) => {
        console.log(status);
        console.log(result);
        if (status === "complete") {
          let list = result.tips || [];
          let obj = {};
          this.poiList = list.reduce((cur, next) => {
            obj[next.id] ? "" : (obj[next.id] = true && cur.push(next));
            return cur;
          }, []);
          console.log(this.poiList);
          this.selectPoiId = this.poiList[0].id;
          this._moveSelect(this.selectPoiId);
        }
      });
    },
    _onSearchByNear(lng, lat) {
      // 搜索方圆1km内的poi
      this.PlaceSearch.searchNearBy("", [lng, lat], 1000, (status, result) => {
        if (status === "complete") {
          this.poiList = result.poiList.pois || [];
          this.selectPoiId = this.poiList[0].id;
          this._moveSelect(this.selectPoiId);
        }
      });
    },
    _onSearch: _.throttle(function (val) {
      if (!this.PlaceSearch) return;
      if (val) {
        // 有搜索内容搜素关键字poi
        this._onSearchByKeyword(val);
      } else {
        const { lng, lat } = this.locationPOI.position;
        this._onSearchByNear(lng, lat);
      }
    }, 300),
    async _moveSelect(poiId) {
      try {
        const result = await this._getPoiDetail(poiId);
        const { lng, lat } = result.location;
        this.Marker.setPosition(new AMap.LngLat(lng, lat));
        this.Map.panTo(new AMap.LngLat(lng, lat));
      } catch (error) {
        console.log("error: ", error);
      }
    },
    /**
     * 获取poi详情
     */
    _getPoiDetail(poiId) {
      return new Promise((resolve, reject) => {
        this.PlaceSearch.getDetails(poiId, (status, result) => {
          if (status === "complete") {
            resolve(result.poiList.pois[0]);
          } else {
            reject();
          }
        });
      });
    },
    /**
     * 计算距离
     */
    async _getDistance() {
      const { location } = await this._getPoiDetail(this.options.poi);
      const { lng, lat } = this.locationPOI.position;
      const target = [location.lng, location.lat];
      const current = [lng, lat];
      const distance = AMap.GeometryUtil.distance(target, current);
      this.distance = Math.ceil(distance);
      this.loadingCompleted = true;
    },
    /**
     * 打开定位
     */
    async _getLocation() {
      const _plus = await isPlus();
      if (_plus) {
        gotoAppSetting();
      }
    },
    /**
     * 地图点击事件
     */
    _mapOnClick(ev) {
      const { lng, lat } = ev.lnglat;
      this._onSearchByNear(lng, lat);
    },
    /**
     * 加载闪动定位信息问题
     */
    _showformattedAddress() {
      if (this.loadingCompleted) {
        if (this.isFar) {
          return this.formattedAddress + ",未在签到地500米范围内，不能签到！";
        } else {
          return this.formattedAddress;
        }
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.map {
  height: 100vh;
  width: 100vw;
  @apply flex flex-col overflow-hidden relative;
  .map-container {
    @apply flex-1;
  }
  .map-search {
    @apply h-1/2 bg-white z-999 rounded-t-10px overflow-hidden flex flex-col;
    padding-bottom: env(safe-area-inset-bottom);
    .search_toolbar {
      height: 44px;
      @apply flex items-center justify-between;
      .toolbar__cancel,
      .toolbar__confirm {
        height: 100%;
        padding: 0 16px;
        font-size: 14px;
        background-color: transparent;
        border: none;
        cursor: pointer;
      }
      .toolbar__confirm {
        color: #1d6fe9;
      }
      .toolbar__cancel {
        color: #969799;
      }
    }
    .search_result {
      @apply overflow-auto flex-1;
    }
  }
  .map-clock-in,
  .map-clock-out {
    @apply absolute bg-white z-999 rounded-10px overflow-hidden flex flex-col;
    left: 12px;
    right: 12px;
    bottom: env(safe-area-inset-bottom);
    .clock_title {
      @apply px-16px py-14px;
      border-bottom: 1px solid #eeeeee;
    }
    .clock_location {
      @apply pb-16px;
      .clock_location__title {
        @apply text-12px font-400;
        color: #666666;
      }
      .clock_location__address {
        @apply flex;
        padding: 6px 0;
        .address {
          @apply text-16px font-400 leading-22px;
          color: #333333;
        }
      }
    }
    .clock_btn {
      @apply pt-20px flex;
      border-top: 1px solid #eeeeee;
    }
  }
  .map-error {
    @apply absolute bg-white z-999 rounded-10px overflow-hidden flex flex-col px-16px py-14px;
    left: 12px;
    right: 12px;
    bottom: env(safe-area-inset-bottom);
    color: #333333;
    .error_title {
      @apply pb-32px text-16px font-500 text-center;
    }
    .error_desc {
      @apply pb-44px text-14px font-400 text-center;
    }
    .error_btn {
      @apply flex;
    }
  }
}
</style>
